package com.mt.roll.wms.dispatch.taskPool.rgvTaskQueue;

import com.mt.roll.core.dal.entity.LocationStorageSub;
import com.mt.roll.core.params.IdParam;
import com.mt.roll.opcua.s7.my.s7connector.api.DaveArea;
import com.mt.roll.opcua.s7.my.s7connector.enmuc.S7Client;
import com.mt.roll.opcua.s7.my.s7connector.service.S7Service;
import com.mt.roll.wms.dispatch.LocalDisPatchService;
import com.mt.roll.wms.dispatch.constant.QGSConstant;
import com.mt.roll.wms.dispatch.enums.machineHand1.MachineHand1Plc2WcsVarEnum;
import com.mt.roll.wms.dispatch.enums.machineHand1.MachineHand1Wcs2PlcVarEnum;
import com.mt.roll.wms.dispatch.taskPool.entity.RGVTask;
import com.mt.roll.wms.service.LocationService;
import com.mt.roll.wms.vo.SubListAndStorageFidVo;
import org.omg.CORBA.PRIVATE_MEMBER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.Callable;

/**
 * @Desc: ""
 * @Author: caixiang
 * @DATE: 2022/3/19 11:25
 */
public class RGV1TaskIssueRunnable<T> implements Callable<T> {
    private final static Logger logger = LoggerFactory.getLogger(RGV1TaskIssueRunnable.class);
    private LocalDisPatchService localDisPatchService;
    private LocationService locationService;
    private S7Client s7Client;
    private RGVTask rgvTask;

    public RGV1TaskIssueRunnable(LocalDisPatchService localDisPatchService, RGVTask rgvTask,LocationService locationService){
        this.localDisPatchService = localDisPatchService;
        this.rgvTask = rgvTask;
        this.locationService = locationService;
        s7Client = S7Client.S7_1200;
    }


    private Object getValue(MachineHand1Plc2WcsVarEnum var) throws Exception {
        return this.s7Client.read(
                DaveArea.DB,
                var.getAreaNumber(),
                var.getByteOffset(),
                var.getBitOffset(),
                var.getLength(),
                var.getStrSize(),
                var.getType()
        );
    }
    private void setValue(MachineHand1Wcs2PlcVarEnum var, Object newValue) throws Exception {
        this.s7Client.write(
                DaveArea.DB,
                var.getAreaNumber(),
                var.getByteOffset(),
                var.getBitOffset(),
                var.getStrSize(),
                var.getType(),
                newValue
        );
    }

    private Integer waitingForTarget(MachineHand1Plc2WcsVarEnum var, Boolean targetValue, Long deadLine) {
        Integer res = 0;
        long start = System.currentTimeMillis();
        while (true){
            try {
                long end = System.currentTimeMillis();
                if((end-start)>deadLine){
                    res = -1;
                    break;
                }

                Boolean now = (Boolean) getValue(var);

                if(targetValue.equals(now)){
                    res = 1;
                    break;
                }
                Thread.sleep(200);
            }catch (Exception e){
                logger.info("opc 访问异常。");
                res = 2;
                break;
            }
        }
        return res;
    }

    //把新的箱子id 和 这个箱子里的所有基板idArray 上传到设备。（所有信息都是覆盖的）
    private Boolean uploadToMachineHand(Integer locationNum) throws Exception {

        IdParam build = IdParam.builder().build();
        build.setId(Long.valueOf(locationNum.toString()));
        SubListAndStorageFidVo data = locationService.getSubListAndStorageFidByLocationNum(build).getData();
        String[] substrateCodes = data.getSubstrateCodes();
        String storageBoxFid = data.getStorageBoxFid();
        MachineHand1Wcs2PlcVarEnum storageIdEnumByLocationNum = MachineHand1Wcs2PlcVarEnum.getStorageIdEnumByLocationNum(locationNum);
        MachineHand1Wcs2PlcVarEnum subIdArrayEnumByLocationNum = MachineHand1Wcs2PlcVarEnum.getSubIdArrayEnumByLocationNum(locationNum);
        if(storageIdEnumByLocationNum==null || subIdArrayEnumByLocationNum==null){
            return false;
        }
        //1. 把这个库位上 更新后的箱子id 传给机械手
        setValue(storageIdEnumByLocationNum, storageBoxFid);
        //2. 把这个库位上 更新后的箱子下的所有基板id（数组） 传给机械手
        setValue(subIdArrayEnumByLocationNum, substrateCodes);
        return true;
    }

    //重置机械手
    private Integer resetRot(Integer locationNum) throws Exception {
        //1.rgv任务完成后，把wcs-plc 的changeok 置为true
        MachineHand1Wcs2PlcVarEnum changeOkEnumByLocationNum = MachineHand1Wcs2PlcVarEnum.getChangeOkEnumByLocationNum(locationNum);
        setValue(changeOkEnumByLocationNum, true);

        //2. plc监听到 changeok 为true后，会把 plc-wcs的 stockfull 置为 false
        MachineHand1Plc2WcsVarEnum stockFullEnumByLocationNum = MachineHand1Plc2WcsVarEnum.getStockFullEnumByLocationNum(locationNum);
        waitingForTarget(stockFullEnumByLocationNum,false, QGSConstant.deadLineTime);
        //3.stockfull 为false的时候再把 wcs-plc 的changeok 置为false
        setValue(changeOkEnumByLocationNum, false);

        if(uploadToMachineHand(locationNum)){
            return 1;
        }else {
            return -1;
        }
    }

    @Override
    public T call() {
        try {
            //wms业务交换+callRgv 逻辑
            List<LocationStorageSub> subList = rgvTask.getSubList();
            int subStorageStatus = rgvTask.getType();
            IdParam idParam = IdParam.builder().build();
            idParam.setId(rgvTask.getLocationNum());
            Integer res = -1;
            if (subStorageStatus==1){
                res = localDisPatchService.locationFull(idParam, subList);
            }else if (subStorageStatus==2){
                res = localDisPatchService.locationEmpty(idParam,subList);
            }
            if(res!=1){
                logger.info("RGV1TaskIssueRunnable,rgv任务执行失败，rgv任务是"+rgvTask.toString()+"失败code:"+res);
            }else {
                //只有当所有都成功的时候才执行机械手复位操作
                //todo 执行机械手复位操作。
                res = resetRot(Integer.valueOf(rgvTask.getLocationNum().toString()));
                logger.info("RGV1TaskIssueRunnable,rgv任务执行成功，rgv任务是"+rgvTask.toString());
            }

            Thread.sleep(5000);
            return (T)res;
        }catch (Exception e){

            logger.info("RGV1TaskIssueRunnable,rgv任务执行失败，rgv任务是"+rgvTask.toString()+" 。。报错原因："+e.getMessage());
            rgvTask=null;
            Boolean fail = false;
            return (T) fail;
        }
    }

}
